package Day013_线程安全.demo03_线程状态;

/**
 * @author zhangyan
 * @date 2020/5/4 11:29
 */
/*
    子线程打印1000次i循环
    主线程打印1000次j循环
    规律:打印1次i循环,打印1次j循环......
    假如 子线程先执行,打印1次i循环,进入无线等待,主线程打印1次j循环,唤醒子线程,主线程进入无线等待....
 */
public class Test1_等待唤醒机制 {
    static Object obj = new Object();

    public static void main(String[] args) throws InterruptedException {
        //创建并启动线程1,进入无线等待
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    System.out.println("线程1准备进去无线等待");
                    try {
                        obj.wait(); //进入无线等待,必须等待其他线程使用锁对象唤醒...此时不会抢占CPU 释放锁对象!
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //刚刚被唤醒时 是锁阻塞状态,需等到线程2释放锁,并获取
                    //线程从无线等待唤醒后并获取到锁对象 会从唤醒的位置继续往下执行
                    System.out.println("线程1被唤醒,并获取锁对象,继续执行...");
                }
            }
        }).start();
        //保证线程1先执行,如果线程2先其抢占CPU,也会指向notify,然后线程1执行到wait进入无线等待...不会被唤醒,卡死
        Thread.sleep(3000);


        //创建并启动线程2,唤醒线程1
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    System.out.println("线程2开始唤醒线程1");
                    obj.notify(); //必须同一个锁对象调用!
                } //释放锁,锁对象被线程1获取
            }
        }).start();
    }
}
